import React, {useState, useEffect, useLayoutEffect} from 'react';

export default function Demo() {
    let [num, setNum] = useState(10);
    let [x, setX] = useState(20);

    // 第一次渲染完 && 每次更新
    // componentDidMount && componentDidUpdate
    // useEffect(() => {
    //     console.log('@1', num, x);
    // });

    // 传递第二个参数为空数组的时候，只在第一次渲染执行
    // useEffect(() => {
    //     console.log('@1', num, x);
    // }, []);

    // 第一次渲染完 && 只有依赖项x状态改变才会触发
    // useEffect(() => {
    //     console.log('@1', num, x);
    // }, [x]);

    // useEffect 不能直接写async，因为async修饰的函数返回promise，useeffect期望返回函数。
    // 解决办法1 使用.then.catch
    // 解决办法2 再包一层函数
    // useEffect(async () => {
    //     let result = await getData();
    // }, [])
    // useEffect(() => {
    //     const next = async () => {
    //         let result = await getData();
    //     };
    //     next();
    // }, []);

    // useEffect 只能出现在函数组件的最外层，不能嵌套到判断，循环等操作中。
    // if(num < 10) {
    //     useEffect(() => {
    //         console.log(10)
    //     }, [num])
    // }

    // 返回回调函数，只会在组件卸载之前触发
    // componentWillUnmount
    useEffect(() => {
        return () => {
            console.log('页面卸载');
        }
    }, []);

    return (
        <div>
            <span>{num}</span>
            <button onClick={() => {
                setNum(num + 1);
            }}>处理</button>

            <br />

            <span>{x}</span>
            <button onClick={() => {
                setX(x + 1);
            }}>处理</button>
        </div>
    )
}

export default function Demo() {
    let [num, setNum] = useState(10);
    let [x, setX] = useState(20);

    // 多个useEffect执行机制
    // 放到effect链表中
    // mountEffect
    // callback 没设置依赖
    // callback 没有依赖
    // callback 依赖num
    // 视图渲染完毕，调用updateEffect，内部有个类似next的方法，依次执行。
    // 修改num的值，组件更新会形成新的闭包2，再次执行effect链表，判断相关callback执行。
    useEffect(() => {
        console.log(1)
    });

    useEffect(() => {
        console.log(2)
    }, []);

    useEffect(() => {
        console.log(3)
    }, [num]);



    return (
        <div>
            <span>{num}</span>
            <button onClick={() => {
                setNum(num + 1);
            }}>处理</button>

            <br />

            <span>{x}</span>
            <button onClick={() => {
                setX(x + 1);
            }}>处理</button>
        </div>
    )
}


export default function Demo() {
    let [num, setNum] = useState(10);

    useEffect(() => {
        let timer = setTimeout(() => {
            console.log(num) // 10
        }, 3000);
    }, []);

    // useEffect(() => {
    //     let timer = setTimeout(() => {
    //         console.log(num) // 10，110
    //     }, 3000);
    // }, [num]);
    


    return (
        <div>
            <span>{num}</span>
            <button onClick={() => {
                setNum(num + 100);
            }}>处理</button>
        </div>
    )
}

export default function Demo() {
    let [num, setNum] = useState(0);

    // useEffect向effect链表中增加的callback函数，会再真实DOM已经彻底渲染完毕后触发执行
    // useEffect(() => {
    //     if(num === 0) {
    //         let random = +String(Math.random().substring(2));
    //         setNum(random);
    //     }
    // }, [num]);

    // useLayoutEffect向effect链表中增加的callback函数，在视图编译完，还没有渲染真是dom之前，触发执行了。
    /**
     * 了解
     * 其函数签名与useEffect相同，但它会在所有的dom变更之后同步调用effect、
     * 可以使用它来读取dom布局并同步触发渲染
     * 在浏览器执行绘制之前，useLayoutEffect内部的更新计划将被同步刷新。
     * 尽可能使用标准的useEffect以避免视觉更新，它会阻塞渲染。
     */
    useLayoutEffect(() => {
        if(num === 0) {
            let random = +String(Math.random().substring(2));
            setNum(random);
        }
    }, [num]);

    return (
        <div onClick={() => { setNum(0); }}>
            {num}
        </div>
    )
}